package com.espirit.finance.core;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;

import com.espirit.eap.util.Functions;
import com.googlecode.cswish.struts.spring.BeanIntrospector;
import com.googlecode.cswish.struts.spring.GenericService;
import com.googlecode.cswish.struts.spring.ObjectFactory;
import com.googlecode.cswish.util.FreemarkerTplEngine;
import com.googlecode.cswish.util.InvocationUtil;
import com.googlecode.cswish.util.bean.ModelUtil;

public abstract class VoucherServiceSupport {
	@Resource
	GenericService genericService;
	
	@Resource
	BeanIntrospector beanIntrospector;
	
	@Resource
	ObjectFactory objectFactory;
	
	@Resource
	CalcAcctFixedStrategy calcAcctFixedStrategy;
	
	@Resource
	CalcAcctGeneralStrategy calcAcctGeneralStrategy;
	
	@Resource
	InvocationUtil invocationUtil;
	
	@Resource
	private Functions functions;
	
	public  void add(TicketAware ticketAware){
		List<AcctItem> results = getAcctItems(ticketAware);
		if (results == null) return ;
		Class<Voucher> voucherClass = getVoucherClazz();
		List<Voucher> children = new ArrayList<Voucher>();
		for(AcctItem acctItem : results){
			if (!StringUtils.isEmpty(acctItem.getTriggerCondition())){
				boolean flag = checkCondition(acctItem.getTriggerCondition(), ticketAware);
				if (!flag) continue;
			}
			
			IAcctCalcStrategy strategy = getStrategy(acctItem);
			BigDecimal amount = strategy.getAmount(ticketAware, acctItem);
			if (amount == null || amount.compareTo(BigDecimal.ZERO) == 0) continue;
			
			Voucher voucher = ModelUtil.newInstance(voucherClass);
			voucher.setTicketAware(ticketAware);
			voucher.setAmount(amount);
			voucher.setAcctItem(acctItem);
			voucher.setAcct(acctItem.getParent());
			voucher.setCreatedOn(new Date());
			voucher.setDc(acctItem.getParent().getDc());
			
			onAdd(voucher);

			voucher = genericService.add(voucher);
			children.add(voucher);
		}
		afterAdd(children, ticketAware);
	}
	
	public abstract Class<Voucher> getVoucherClazz();
	public abstract <T extends AcctItem> List<T> getAcctItems(TicketAware ticketAware);
	public abstract void onAdd(Voucher voucher);
	public abstract void afterAdd(List<Voucher> children, TicketAware ticketAware);
	
	private IAcctCalcStrategy getStrategy(AcctItem acctItem){
		Acct acct = acctItem.getParent();
		Integer strategy = acct.getStrategy();
		if (Acct.STRATEGY_FIXED.equals(strategy)){
			return calcAcctFixedStrategy;
		} else if (Acct.STRATEGY_GENERAL.equals(strategy)){
			return calcAcctGeneralStrategy;
		} else {
			return calcAcctGeneralStrategy;
		}
	}
	
	public boolean checkCondition(String triggerCondition, TicketAware model) {
			if (triggerCondition == null || triggerCondition.isEmpty()){
				return true;
			} else {
//				String condtion = triggerCondition.replaceAll(" > ", " gt ");
//				condtion = condtion.replaceAll(" > ", " gt ");
//				condtion = condtion.replaceAll(" < ", " lt ");
//				condtion = condtion.replaceAll(" >= ", " gte ");
//				condtion = condtion.replaceAll(" <= ", " lte ");
//				condtion = condtion.replaceAll(" and ", " && ");
//				condtion = condtion.replaceAll(" or ", " || ");
				
				Map<String, Object> parameters = new HashMap<String, Object>();
				invocationUtil.forceLoadModelAndResults(parameters);
				parameters.put("fn", functions);
				parameters.put("model", model);
//				parameters.put("action", new MapContext(action));
				
				Map<String, Object> traceResult = new HashMap<String, Object>(4);
				traceResult.put("result", null);

				FreemarkerTplEngine.getInstance().execute(triggerCondition, parameters, traceResult);
				String result = (String) traceResult.get("result");
				return Boolean.valueOf(result);
			}
		}
}
